package com.huayue.point.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.huayue.point.api.PointServiceApi;
import com.huayue.point.bean.PointDto;
import com.huayue.point.bean.PointPo;
import com.huayue.point.bean.RankDto;
import com.huayue.point.bean.RankPo;
import com.huayue.point.mapper.PointMapper;
import com.huayue.user.api.UserServiceApi;
import com.huayue.user.bean.UserDto;
import com.huayue.user.exception.ParamException;
import com.huayue.user.exception.UserNotExistException;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;

import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class PointService implements PointServiceApi {
    @Reference
    private UserServiceApi userServiceApi;
    @Autowired
    private PointMapper pointMapper;
    @Override
    public Boolean add(Integer point, Collection<String> noList, String mark) throws ParamException, UserNotExistException {
        Collection<UserDto> userDtos = userServiceApi.queryByNo(noList);
        Map<String,Integer> userNoToIdMap = new HashMap<>();
        userDtos.forEach(u->{
            userNoToIdMap.put(u.getNo(),u.getId());
        });
        List<String> errNoList = new ArrayList<>();
        List<PointPo> pointPos = new ArrayList<>();
        for (String no : noList) {
            PointPo pointPo = new PointPo();
            if (!userNoToIdMap.containsKey(no)) {
                errNoList.add(no);
                continue;
            }
            pointPo.setMark(mark);
            pointPo.setPoint(point);
            Integer userId = userNoToIdMap.get(no);
            pointPo.setUserId(userId);
            pointPo.setUpdateTime(new Timestamp(System.currentTimeMillis()));
            pointPos.add(pointPo);
        }
        if (errNoList.size() > 0) {
            throw new UserNotExistException("User No." + String.join("," , errNoList) + " not exist.");
        }
        pointPos.forEach(pointPo -> pointMapper.insert(pointPo));
        return true;
    }

    /**
     * 根据工号查询用户id
     * @param no
     * @return
     * @throws ParamException
     * @throws UserNotExistException
     */
    private Integer getUserIdByUserNo(String no) throws ParamException, UserNotExistException {
        UserDto userDto = userServiceApi.queryByNo(no);
        if (userDto == null) {
            throw new UserNotExistException("User No." + no + " not exist.");
        }
        return userDto.getId();
    }

    @Override
    public Collection<PointDto> queryDetail(String no) throws ParamException, UserNotExistException {
        Integer userId = getUserIdByUserNo(no);
        LambdaQueryWrapper<PointPo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PointPo::getUserId, userId);
        List<PointPo> pointPos = pointMapper.selectList(wrapper);
        List<PointDto> pointDtos = JSON.parseObject(JSON.toJSONString(pointPos), new TypeReference<List<PointDto>>() {
        });
        return pointDtos;
    }

    @Override
    public Integer querySum(String no) throws UserNotExistException, ParamException {
        Integer userId = getUserIdByUserNo(no);
        Integer integer = pointMapper.querySum(userId);
        return integer;
    }

    @Override
    public Collection<RankDto> rank() throws ParamException {
        Collection<RankPo> ranks = pointMapper.rank();
        Set<Integer> userIds = ranks.stream().map(rank -> rank.getUserId()).collect(Collectors.toSet());
        Collection<UserDto> userDtos = userServiceApi.queryById(userIds);
        Map<Integer,String> userIdToUserMap = new HashMap<>();
        userDtos.forEach(u->
            userIdToUserMap.put(u.getId(), u.getName())
        );
        List<RankDto> result = new ArrayList<>();
        Iterator<RankPo> iterator = ranks.iterator();
        int i = 1;
        while (iterator.hasNext()) {
            RankPo next = iterator.next();
            if(!userIdToUserMap.containsKey(next.getUserId())){
                continue;
            }
            RankDto rankDto = new RankDto();
            rankDto.setPoint(next.getPoint());
            rankDto.setRank(i);
            rankDto.setName(userIdToUserMap.get(next.getUserId()));
            result.add(rankDto);
            i ++;
        }
        return result;
    }

    @Override
    public Boolean update(Integer id, Integer point) {
        PointPo pointPo = pointMapper.selectById(id);
        if (pointPo == null) {
            return false;
        }
        pointPo.setPoint(point);
        pointMapper.updateById(pointPo);
        return true;
    }

    @Override
    public Boolean delete(Integer id) {
        int i = pointMapper.deleteById(id);
        if (i <= 0) {
            return false;
        } else {
            return true;
        }
    }
}
